package com.wh.weibo.service.impl;

import com.wh.weibo.facade.TopicService;
import com.wh.weibo.job.SyncDiscussCountJob;
import com.wh.weibo.mapper.TopicMapper;
import com.wh.weibo.mapper.UserTopicFollowMapper;
import com.wh.weibo.mapper.UserTopicReadMapper;
import com.wh.weibo.model.ServiceResult;
import com.wh.weibo.model.Topic;
import com.wh.weibo.model.UserTopicFollow;
import com.wh.weibo.model.UserTopicRead;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.Set;

/**
 * @author WeiHong
 * @date 2019/7/11 10:57
 */
@Service("topicService")
public class TopicServiceImpl implements TopicService {

    /**
     * 微博话题讨论数KEY
     */
    private static final String TOPIC_DISCUSS_REDIS_KEY_PREFIX = "TOPIC:DISCUSS:COUNT:";

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private TopicMapper topicMapper;

    @Resource
    private UserTopicFollowMapper userTopicFollowMapper;

    @Resource
    private UserTopicReadMapper userTopicReadMapper;

    @PostConstruct
    public void init() throws SchedulerException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        JobDetail jobDetail = JobBuilder.newJob(SyncDiscussCountJob.class).withIdentity("sync","sync").build();
        jobDetail.getJobDataMap().put("springBean",this);
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger","trigger").withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")).build();

        scheduler.scheduleJob(jobDetail,trigger);
        scheduler.start();
    }

    /**
     * 创建微博
     *
     * @param topic
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult<Topic> create(Topic topic) {
        ServiceResult<Topic> serviceResult = new ServiceResult<>();
        if (StringUtils.isAnyBlank(topic.getTitle(), topic.getDescription())) {
            serviceResult.setSuccess(false);
            serviceResult.setErrorMsg("入参错误");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return serviceResult;
        }

        try {
            topicMapper.insertSelective(topic);
        } catch (DuplicateKeyException ex) {
            serviceResult.setSuccess(false);
            serviceResult.setErrorMsg("话题已存在，创建失败");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return serviceResult;
        }
        serviceResult.setData(topic);
        return serviceResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult increaseDiscussCount(Integer id) {
        //调用数据库将对应话题的讨论数量+1
        /*topicMapper.increaseDiscussCount(id);*/
        //改为采用缓存
        //调用redis将对应话题的讨论数量+1
        redisTemplate.opsForValue().increment(TOPIC_DISCUSS_REDIS_KEY_PREFIX + id, 1);
        return new ServiceResult();
    }

    @Override
    public ServiceResult<Topic> get(Integer id) {
        ServiceResult<Topic> serviceResult = new ServiceResult<>();
        if (null == id) {
            serviceResult.setSuccess(false);
            serviceResult.setErrorMsg("入参错误");
            return serviceResult;
        }
        Topic topic = topicMapper.selectByPrimaryKey(id);
        fillDiscountCount(topic);
        serviceResult.setData(topic);
        return serviceResult;
    }

    @Override
    public ServiceResult<Topic> getByTitle(String title) {
        ServiceResult<Topic> serviceResult = new ServiceResult<>();
        if (StringUtils.isEmpty(title)) {
            serviceResult.setSuccess(false);
            serviceResult.setErrorMsg("入参错误");
            return serviceResult;
        }
        Topic topic = topicMapper.selectByTitle(title);
        fillDiscountCount(topic);
        serviceResult.setData(topic);
        return serviceResult;
    }

    @Override
    public ServiceResult<List<Topic>> selectList() {
        ServiceResult<List<Topic>> listServiceResult = new ServiceResult<>();
        List<Topic> list = topicMapper.selectList();
        list.forEach(topic -> fillDiscountCount(topic));
        listServiceResult.setData(list);
        return listServiceResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult follow(Integer userId, Integer topicId) {
        ServiceResult serviceResult = new ServiceResult();
        ServiceResult<Topic> topicServiceResult = this.get(topicId);
        if (null == topicServiceResult) {
            serviceResult.setSuccess(false);
            serviceResult.setErrorMsg("话题服务通信异常");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return serviceResult;
        } else if (!topicServiceResult.isSuccess() || null == topicServiceResult.getData()) {
            serviceResult.setSuccess(false);
            serviceResult.setErrorMsg("对应的话题不存在或者服务异常");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return serviceResult;
        }
        Topic topic = topicServiceResult.getData();

        UserTopicFollow follow = new UserTopicFollow();
        follow.setUserId(userId);
        follow.setTopicId(topicId);

        try {
            userTopicFollowMapper.insertSelective(follow);
        } catch (DuplicateKeyException ex) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return serviceResult;
        }
        topicMapper.increaseFollowCount(topicId);
        return serviceResult;
    }

    @Override
    public ServiceResult read(Integer userId, Integer topicId) {
        ServiceResult serviceResult = new ServiceResult();
        ServiceResult<Topic> topicServiceResult = this.get(topicId);
        if (null == topicServiceResult) {
            serviceResult.setSuccess(false);
            serviceResult.setErrorMsg("话题服务通信异常");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return serviceResult;
        } else if (!topicServiceResult.isSuccess() || null == topicServiceResult.getData()) {
            serviceResult.setSuccess(false);
            serviceResult.setErrorMsg("对应的话题不存在或者服务异常");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return serviceResult;
        }
        Topic topic = topicServiceResult.getData();

        UserTopicRead read = new UserTopicRead();
        read.setUserId(userId);
        read.setTopicId(topicId);

        try {
            userTopicReadMapper.insertSelective(read);
        } catch (DuplicateKeyException ex) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return serviceResult;
        }
        topicMapper.increaseReadCount(topicId);
        return serviceResult;
    }

    @Override
    public void syncTopicDiscussCount() {
        //获取所有的微博话题讨论数KEY，注意后面的*
        Set<String> keys = redisTemplate.keys(TOPIC_DISCUSS_REDIS_KEY_PREFIX + "*");
        //遍历KEY
        keys.forEach(key->{
            Integer count = (Integer) redisTemplate.opsForValue().get(key);
            //替换掉前缀，获得topicId
            Integer topicId =  new Integer(key.replace(TOPIC_DISCUSS_REDIS_KEY_PREFIX,""));
            if(count == null || topicId == null){
                return;
            }
            topicMapper.updateDiscussCount(topicId,count);
        });
    }

    /**
     * 修改热门话题的讨论数
     *
     * @param topic
     */
    private void fillDiscountCount(Topic topic){
        if(topic == null){
            return;
        }
        Integer discountCount = (Integer) redisTemplate.opsForValue().get(TOPIC_DISCUSS_REDIS_KEY_PREFIX + topic.getId());
        if(discountCount != null){
            topic.setDiscussCount(discountCount);
        }else{
            //若redis内get不到，用数据库的替换掉
            redisTemplate.opsForValue().set(TOPIC_DISCUSS_REDIS_KEY_PREFIX + topic.getId(),topic.getDiscussCount());
        }
    }

}
